package com.glq1218.foreground.config;

import com.glq1218.authentication.filter.JwtAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.Arrays;
import java.util.stream.Stream;

/**
 * @author glq1218
 */
@Configuration
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
    private final JwtAuthenticationFilter jwtAuthFilter;
    private final AuthenticationEntryPoint authenticationEntryPoint;

    private final AccessDeniedHandler accessDeniedHandler;

    /**
     * 放行Swagger
     */
    public static final String[] SWAGGER_WHITELIST = {
            "/swagger-ui/index.html",
            "/swagger-ui.html",
            "/swagger-ui/**",
            "/v3/api-docs/**",
            "/v3/api-docs",
            "/doc.html",
            "/swagger-resources",
            "/swagger-resources/**",
            "/webjars/**"
    };


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // 允许跨域
                .cors().and()
                // 关闭默认登出
                .logout().disable()
                // 关闭csrf
                .csrf().disable()
                // 不通过Session获取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeHttpRequests()
                // 允许匿名访问
                .requestMatchers(requestMatchersAnonymous()).anonymous()
                // 静态资源不需要任何限制
                .requestMatchers(HttpMethod.GET, requestMatchersPermitAll()).permitAll()
                // 除上面外的所有请求全部放行
                .anyRequest().permitAll().and()
                // 指定异常处理器
                .exceptionHandling()
                // 认账异常处理
                .authenticationEntryPoint(authenticationEntryPoint)
                // 授权异常处理
                .accessDeniedHandler(accessDeniedHandler).and()
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    /**
     * 不需要任何限制url（静态资源）
     *
     * @return 字符串数组
     */
    private String[] requestMatchersPermitAll() {
        return new String[]{"/*.html"};
    }

    /**
     * 允许匿名访问url
     *
     * @return 字符串数组
     */
    private String[] requestMatchersAnonymous() {
        String[] anonymous = {
                "/api/auth/**"
        };
        return Stream.concat(Arrays.stream(SWAGGER_WHITELIST), Arrays.stream(anonymous)).toArray(String[]::new);
    }
}
